#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;



//成员变量和成员函数分开存储
//只有只有只有非静态成员变量才属于类的对象上

class Person
{
public:
	int m_A;		//非静态成员变量，属于类的对象上

	static int m_a;	//静态成员变量和函数，不属于类的对象上

	void func()		//非静态成员函数 不属于类的对象上
	{

	}
};

void test01()
{
	Person p;
	cout << "size of p: " << sizeof(p) << endl;
	//空对象也分配一个字节空间，为了区分空对象所在内存位置
	//每个空对象应该有一个无独一无二的内存地址
}


void test02()
{
	Person p;
	cout << "size of p: " << sizeof(p) << endl;
	//所占字节为4，就是int m_A; 的内存大小
}

int main()
{
	//test01();
	test02();
	system("pause");
	return 0;
}





//this指针(无需定义，隐含每一个非静态成员函数内的一种指针)
//this指针指向被调用的成员函数所属的对象,即 创建对象p1 后this就指向p1
//this只能用于非静态成员函数内部

/*
this指针用途
1.当形参和成员变量同名时，可用this指针来区分。
2.在类的非静态成员函数中可使用return *this;返回对象本身
*/

class Person
{
public:
	int age;

	Person(int age) //函数形参和成员变量同名，无法区分
	{
		this->age = age;	//this->age代表成员变量
	}

	Person& PersonAdd(Person& p) //返回本体用引用的方式返回
	{
		this->age += p.age;
		return *this;
		//this是指向对象的指针，*this解引用
	}
};



void test01()
{
	Person p1(18);
	cout << "age: " << p1.age << endl;
}

void test02()
{
	Person p2(18);
	Person p3(12);
	//链式编程思想
	p2.PersonAdd(p3).PersonAdd(p3).PersonAdd(p3);
	cout << "p2.age=" << p2.age << endl;
}

int main()
{
	//test01();
	test02();
	return 0;
}




//空指针访问成员函数

class Person
{
public:

	void showClassName()
	{
		cout << "this is Person class." << endl;
	}
	void showPersonage()
	{
		//防止跨界访问
		if (this == NULL)
			return;
		cout << "age= " << this->m_Age << endl;
	}
	int m_Age = 10;
};

void test01()
{
	Person* p = NULL; //即this = NULL
	p->showClassName();
	//传入指针为空，无法访问其中属性
	p->showPersonage();
}

int main()
{
	test01();
	return 0;
}




//const修饰成员函数
/*
常函数即成员函数后加const的函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable，在常函数中依然可以修改

声明对象前加const称为常对象
常对象只能调用常函数
*/

class Person
{
public:
	//this指针的本质 是 指针常量 指向不能修改
	void showPerson() const	//加了const后this指向的值也不能修改
	{
		//m_A = 100;	//加了const后成员属性不能修改
		m_B = 100;
	}
	int m_A;
	mutable int m_B;	//加了mutable后可以修改
};
void test01()
{
	const Person p;	//在对象前加const，变为常对象
	p.m_B = 12; //m_B可以修改

	p.showPerson();	//只能调用常对象
}





//友元（关键字为friend）
//友元可以让一个函数或者类访问另一个类中的私有成员（private）
//
//
class Building;

class GoodSister
{
public:
	GoodSister();

	void visit01();	//让visit01函数可以发访问Building中私有成员

	Building* building;
};

class Building
{
	//设置友元，goodfriend函数可以访问私有成员
	friend void goodfriend(Building* building);		//全局函数做友元

	//设置友元，GoodGay类可以访问私有成员
	friend class GoodGay;				//类做友元

	//设置友元，类GoodSister的visit01成员函数可以访问私有成员
	friend void GoodSister::visit01();		//成员函数做友元

public:
	Building()
	{
		m_SittingRoom = "客厅";
		m_BedRoom = "卧室";
	}

public:
	string m_SittingRoom;

private:
	string m_BedRoom;
};

class GoodGay
{
public:
	GoodGay();
	void visit();
private:
	Building* building;
};

//类外也可以写构造函数
GoodGay::GoodGay()	//即GoodGay构造函数里面创建Building对象
{
	//创建对象
	building = new Building;
}

void GoodGay::visit()
{
	cout << "好基友类正在访问: " << building->m_SittingRoom << endl;
	cout << "好基友类正在访问: " << building->m_BedRoom << endl;
}





GoodSister::GoodSister()
{
	building = new Building;
}

void GoodSister::visit01()
{
	cout << "visit01函数正在访问： " << building->m_SittingRoom << endl;
	
	cout << "visit01函数正在访问： " << building->m_BedRoom << endl;
}


void goodfriend(Building* building)
{
	cout << "好朋友的全局函数，正在访问: " << building->m_SittingRoom << endl;
	cout << "好朋友的全局函数，正在访问: " << building->m_BedRoom << endl;
}




void test01()
{
	Building building;
	goodfriend(&building);
}

void test02()
{
	GoodGay goodgay;
	goodgay.visit();
}

void test03()
{
	GoodSister goodsister;
	goodsister.visit01();
	cout << goodsister.building->m_SittingRoom << endl;
}

int main()
{
	//test01();
	//test02();
	test03();
	return 0;
}






class Building;
class GoodSister
{
public:

	GoodSister();
	void visit01();

private:
	Building* building;
};

class Building
{
	//设置友元，goodfriend函数可以访问私有成员
	friend void goodfriend(Building* building);		//全局函数做友元

	//设置友元，GoodGay类可以访问私有成员
	friend class GoodGay;				//类做友元

	//设置友元，类GoodSister的visit01成员函数可以访问私有成员
	friend void GoodSister::visit01();		//成员函数做友元


public:
	Building();
public:
	string m_SittingRoom;
private:
	string m_BedRoom;
};

Building::Building()
{
	m_BedRoom = "卧室";
	m_SittingRoom = "客厅";
}

GoodSister::GoodSister()
{
	building = new Building;
}

void GoodSister::visit01()
{
	cout << "好姐妹正在访问" << building->m_BedRoom << endl;
	cout << "好姐妹正在访问" << building->m_SittingRoom << endl;
}

class GoodGay
{
public:
	GoodGay();
	void visit();
private:
	Building* building;
};

//类外也可以写构造函数
GoodGay::GoodGay()	//即GoodGay构造函数里面创建Building对象
{
	//创建对象
	building = new Building;
}

void GoodGay::visit()
{
	cout << "好基友类正在访问: " << building->m_SittingRoom << endl;
	cout << "好基友类正在访问: " << building->m_BedRoom << endl;
}

void goodfriend(Building* building)
{
	cout << "好朋友的全局函数，正在访问: " << building->m_SittingRoom << endl;
	cout << "好朋友的全局函数，正在访问: " << building->m_BedRoom << endl;
}

void test01()
{
	Building building;
	goodfriend(&building);
}

void test02()
{
	GoodGay goodgay;
	goodgay.visit();
}

void test03()
{
	GoodSister goodsister;
	goodsister.visit01();
}

int main()
{
	//test01();
	//test02();
	test03();
	return 0;
}







//运算符重载
//对已有的运算符重新进行定义，赋予其另一种功能
//以适应不同的数据类型（自定义的）


//加号（+）运算符重载
//1.成员函数重载+号
class Person
{
public:
	//Person operator+(Person p)
	//{
	//	Person temp;
	//	temp.m_A = this->m_A + p.m_A;
	//	temp.m_B = this->m_B + p.m_B;
	//	return temp;
	//}

	int m_A;
	int m_B;

};

//2.全局函数重载+号
Person operator+(Person p1, Person p2)
{
	Person temp;
	temp.m_A = p1.m_A + p2.m_B;
	temp.m_B = p1.m_A + p2.m_B;
	return temp;
}
//同一个符号只能重载一次,不能同时重载

void test01()
{
	Person p1;
	p1.m_A = 10;
	p1.m_B = 10;

	Person p2;
	p2.m_A = 20;
	p2.m_B = 20;

	Person p3;
	
	//成员函数重载本质调用
	//p3 = p1.operator+(p2);

	//全局函数重载本质调用
	//p3 = operator+(p1, p2);

	//均可化简为
	p3 = p1 + p2;
	cout << "p3.m_A= " << p3.m_A << endl;
	cout << "p3.m_B= " << p3.m_B << endl;
}

int main()
{
	test01();
	int a = 10;
	int b = 10;
	int c = a + b;		//重载后任然保留原有功能，
						//并且运算符重载也可以发生函数重载
						//即对于加号来说，不同数据类型相加只要重载了，都能用+表示
	cout << c << endl;
	return 0;
}
//对于内置的数据类型的表达式的运算符是不可能改变的



//左移(<<)运算符重载
//cout 的类型为ostream
//cin  的类型为istream

class Person
{
	friend ostream& operator<<(ostream& cout, Person& p);

public:
	Person()
	{
		m_A = 10;
		m_B = 20;
	}

	//1.成员函数重载
	//ostream &operator<<(ostream &cout)
	//{
	//	cout << "m_A= " << this->m_A << "  m_B= " << this->m_B << endl;
	//	return cout;
	// }

private:
	
	int m_A;
	int m_B;
};

//2.全局函数重载
ostream& operator<<(ostream& cout, Person& p)
{
	cout << "m_A= " << p.m_A << "  m_B= " << p.m_B << endl;
	return cout;
}

void test01()
{
	Person p1;

	//成员函数重载标准调用
	//p1.operator<<(cout);
	
	//成员函数重载简化
	//p1 << cout;		//一般不用成员函数重载<<，因为只能重载出反的

	//全局函数重载标准调用
	//operator<<(cout, p1);

	//全局函数重载简化
	cout << p1 << endl;

}

int main()
{
	test01();
	return 0;
}



//递增运算符(++)重载

class MyInteger
{
	friend ostream& operator<<(ostream& cout, MyInteger p);

public:
	MyInteger()
	{
		m_Num = 0;
	}

	//重载前置++运算符	(前置返回引用，要加&)
	MyInteger& operator++()
	{
		++(this->m_Num);
		return *this;
	}

	//重载后置++运算符(后置返回值不加&)
	MyInteger operator++(int)		//int代表占位参数，可用于区分前置和后置,表示后置
	{
		MyInteger temp = *this;
		m_Num++;
		return temp;
	}
private:
	int m_Num;
};

ostream& operator<<(ostream& cout, MyInteger myint)
{
	cout << myint.m_Num << endl;
	return cout;
}

void test01()
{
	MyInteger myint;
	cout << ++(++myint) << endl;
	cout << myint << endl;
}

void test02()
{
	MyInteger myint;
	cout << myint++ << endl;
	cout << myint << endl;
}

int main()
{
	//test01();
	test02();

	return 0;
}


//递减运算符(--)重载
class Myinteger
{
	friend ostream& operator<<(ostream& cout, Myinteger myint);

public:
	Myinteger()
	{
		m_Num = 10;
	}

	//重载前置--
	Myinteger& operator--()
	{
		this->m_Num--;
		return *this;
	}

	//重载后置--
	Myinteger operator--(int)	
	{
		Myinteger temp = *this;
		this->m_Num--;
		return temp;
	}
private:

	int m_Num;
};

ostream& operator<<(ostream& cout, Myinteger myint)
{
	cout << myint.m_Num << endl;
	return cout;
}

void test01()
{
	Myinteger myint;
	cout << --myint ;
	cout << myint--;
	cout << myint;
}


int main()
{
	test01();
	return 0;
}





//赋值运算符(=)重载 
//c++编译器给一个类至少添加4个函数
//默认构造，默认析构，默认拷贝构造，赋值运算符(operator=)

class Person
{
public:

	Person(int age)
	{
		m_Age = new int(age);
	}

	//重载=
	Person& operator=(Person& p1)
	{
		//编译器提供的浅拷贝
		//this->m_Age = p1.m_Age;

		//深拷贝
		//应该先判断自身是否有属性在堆区，如果有先释放
		if (this->m_Age != NULL)
		{
			delete this->m_Age;
			this->m_Age = NULL;
		}

		this->m_Age = new int(*p1.m_Age);
		return *this; 
	}


	~Person()
	{
		if (m_Age != NULL)
		{
			delete m_Age;
			m_Age = NULL;
		}
		 
	}
	int *m_Age;
};

void test01()
{
	Person p1 = 10;

	Person p2 = 20; 

	Person p3 = 30;
	p3 = p2 = p1;		//这里的=是编译器提供的浅拷贝，释放内存时p1和p2都会释放堆区的同一个区域
						//重复释放，程序崩溃，应该用深拷贝解决问题
	cout << "p1.m_Age = " << *p1.m_Age << endl;
	cout << "p2.m_Age = " << *p2.m_Age << endl;
	cout << "p3.m_Age = " << *p3.m_Age << endl;
}

int main()
{
	test01();

	system("pause");
	return 0;
}




//关系运算符(>, <, ==, >=, <=， !=)重载
//本例只重载==，其余类似

class Person
{
public:
	Person(string name, int age)
	{
		m_Name = name;
		m_Age = age;
	}
	//重载==
	bool operator==(Person p)
	{
		if (this->m_Age == p.m_Age && this->m_Name == p.m_Name)
			return 1;
		else
			return 0;
	}

	string m_Name;
	int m_Age;
};

void test01()
{
	Person p1("张三", 18);

	Person p2("张三", 18);

	if (p1 == p2)
	{
		cout << "p1和p2相等。" << endl;
	}
	else
	{
		cout << "p1和p2不相等。" << endl;
	}

}
int main()
{
	test01();
	return 0;
}




//函数调用运算符()重载
//重载后的使用方式非常像函数的调用，因此成为仿函数
//仿函数没有固定写法，非常灵活

class MyPrint
{
public:
	void operator()(string test)
	{
		cout << test << endl;
	}
};

void print02(string test)
{
	cout << test << endl;
}

void test01()
{
	MyPrint print;
	print.operator()("hello world!");
	print("hello world!");			//对象使用重载后的()，仿函数
	print02("hello world!");		//函数调用
}

//仿函数非常灵活，没有固定写法
//加法类

class myadd
{
public:
	int operator()(int num1, int num2)
	{
		return num1 + num2;
	}

};

void test02()
{
	myadd add1;
	cout << add1(100, 200) << endl;

	//匿名函数对象
	cout << myadd()(100, 200) << endl;	//myadd()是一个匿名对象，当前行执行完立即释放
}
int main()
{
	//test01();
	test02();
	return 0;
}










